﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.StsAdmin;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.Xml;
using System.Diagnostics;

namespace stsadm.webconfig.Commands
{
    public class webconfig : ISPStsadmCommand
    {
        string _url = string.Empty;
        string _File = string.Empty;
        SPWebApplication _chosenWebApp = null;
        ConfigMode _configMode;
        string _Owner = string.Empty;

        private enum ConfigMode
        {
            Install,
            Remove
        }

        private struct ModificationEntry
        {
            public string Name;
            public string Path;
            public string Value;
            public SPWebConfigModification.SPWebConfigModificationType ModType;

            public ModificationEntry(string Name, string Path, string Value, SPWebConfigModification.SPWebConfigModificationType ModType)
            {
                this.Name = Name;
                this.Path = Path;
                this.Value = Value;
                this.ModType = ModType;
            }
        }

        #region ISPStsadmCommand Members

        public string GetHelpMessage(string command)
        {
            return "-url <URL of web application to apply config changes on> " + Environment.NewLine + "-configfile <configuration file to use in 12\\Config>";
        }

        public int Run(string command, System.Collections.Specialized.StringDictionary keyValues, out string output)
        {
            command = command.ToLowerInvariant();

            this._url = keyValues["url"];
            this._File = keyValues["configfile"];

            if (string.IsNullOrEmpty(this._File))
            {
                throw new ArgumentException("missing configfile parameter");
            }

            switch (command)
            {
                case "webconfig_apply":
                    this._configMode = ConfigMode.Install;
                    break;
                case "webconfig_remove":
                    this._configMode = ConfigMode.Remove;
                    break;
                default:
                    throw new InvalidOperationException();
            }

            addRemoveDataEntries();

            output = this._url + " web.confg file configured successfully";

            return 0;
        }

        #endregion

        private void addRemoveDataEntries()
        {
            SPWebApplication webApp = SPWebApplication.Lookup(new Uri(this._url));
            this._chosenWebApp = webApp;

			foreach (ModificationEntry mod in getConfigurationMods())//getMods())
                addRemoveMod(mod);

            this._chosenWebApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
            this._chosenWebApp.Update();
        }


        private void addRemoveMod(ModificationEntry mod)
        {
            if (this._configMode == ConfigMode.Install)
                this._chosenWebApp.WebConfigModifications.Add(createModification(mod));
            else
                this._chosenWebApp.WebConfigModifications.Remove(createModification(mod));
        }

        private SPWebConfigModification createModification(ModificationEntry modEntry)
        {
            SPWebConfigModification mod = new SPWebConfigModification(modEntry.Name, modEntry.Path);
            mod.Owner = this._Owner;
            mod.Sequence = 0;
            mod.Type = modEntry.ModType;
            mod.Value = modEntry.Value;
            return mod;
        }

		//private List<ModificationEntry> getMods()
		//{
		//    List<ModificationEntry> mods = new List<ModificationEntry>();

		//    if (this._configMode == ConfigMode.Install)
		//        mods = getInstallMods();

		//    if (this._configMode == ConfigMode.Remove)
		//        mods = getRemoveMods();

		//    return mods;
		//}

        private List<ModificationEntry> getConfigurationMods()
        {
            List<ModificationEntry> mods = new List<ModificationEntry>();

            List<ModificationEntry> xmlMods = getCurrentMods();

            if (xmlMods != null && xmlMods.Count > 0)
            {
                foreach (ModificationEntry xmlMod in xmlMods)
                {
                    mods.Add(xmlMod);
                }
            }

            return mods;
        }

        private XmlDocument getFileDoc()
        {
            XmlDocument configEntryDocument = new XmlDocument();
            configEntryDocument.PreserveWhitespace = true;
            string path = "C:\\Program Files\\Common Files\\Microsoft Shared\\web server extensions\\12\\CONFIG\\" + this._File;
            configEntryDocument.Load(path);

            return configEntryDocument;
        }

        private List<ModificationEntry> getCurrentMods()
        {

#if DEBUG
Debugger.Launch();
#endif

            List<ModificationEntry> mods = new List<ModificationEntry>();
            XmlDocument fileDoc = getFileDoc();
            XmlNode installNode = fileDoc.SelectSingleNode("/ConfigEntries");
            if (installNode != null && installNode.HasChildNodes)
            {
                XmlAttribute ownerAttrib = installNode.Attributes["owner"];
                this._Owner = ownerAttrib.Value;
                foreach (XmlNode node in installNode.ChildNodes)
                {
                    if (node is XmlElement)
                        mods.Add(getModFromNode(node));
                }
            }

            return mods;
        }        

        private ModificationEntry getModFromNode(XmlNode node)
        {
            ModificationEntry mod = new ModificationEntry();
            foreach (XmlNode childNode in node.ChildNodes)
            {
                if (childNode is XmlElement)
                {
                    XmlElement element = childNode as XmlElement;
                    if (element.Name == "Name")
                    {
                        mod.Name = getElementValue(element.InnerText);
                        continue;
                    }

                    if (element.Name == "Path")
                    {
                        mod.Path = getElementValue(element.InnerText);
                        continue;
                    }

                    if (element.Name == "Value")
                    {
                        mod.Value = getElementValue(element.InnerText);
                        continue;
                    }

                    if (element.Name == "ModType")
                    {
                        mod.ModType = (Microsoft.SharePoint.Administration.SPWebConfigModification.SPWebConfigModificationType)Enum.Parse(typeof(Microsoft.SharePoint.Administration.SPWebConfigModification.SPWebConfigModificationType), getElementValue(element.InnerText), true);
                        continue;
                    }
                }
            }

            return mod;
        }

        private string getElementValue(string rawValue)
        {
            if (string.IsNullOrEmpty(rawValue))
                return rawValue;

            string elementValue = rawValue.Replace("<![CDATA[", "");
            elementValue = elementValue.Replace("]]>", "");

            return elementValue;
        }
    }
}